/*
 * DBTable_Accounts.c
 *      Author: DePhille
 */


#include "DBTable_Accounts.h"


/**
 * Inserts an account entry into the database.
 *
 * @param	account	The account entry to insert.
 * @returns	True on success, False otherwise.
 */
static gboolean	PC_DBTable_Accounts_Insert(const pc_dbtable_account* account) {
	sqlite3_stmt*	stmt;	// Clean-up: Yes

	// Check input:
	if (!account) {
		purple_debug_warning("PidginCote", "PC_DBTable_Accounts_Insert: Missing 'account' parameter.\r\n");
		return FALSE;
	}

	// Check DB connection:
	if (!pc_logDB) {
		purple_debug_error("PidginCote", "PC_DBTable_Accounts_Insert: Unable to find an active DB connection.\r\n");
		return FALSE;
	}

	// Make statement:
	stmt = NULL;
	if (sqlite3_prepare_v2(pc_logDB, "INSERT INTO Accounts (protocol, account) VALUES (?, ?);", -1, &stmt, NULL) != SQLITE_OK) {
		purple_debug_error("PidginCote", "PC_DBTable_Accounts_Insert: Unable to prepare statement due to SQLite error.\r\n");
		return FALSE;
	} else if (!stmt) {
		purple_debug_error("PidginCote", "PC_DBTable_Accounts_Insert: Unable to prepare statement due to unknown error.\r\n");
		return FALSE;
	}

	// Bind variables:
	if (sqlite3_bind_text(stmt, 1, account->protocol, -1, SQLITE_STATIC) != SQLITE_OK) {
		purple_debug_error("PidginCote", "PC_DBTable_Accounts_Insert: Unable to bind first value.\r\n");
		return FALSE;
	}
	if (sqlite3_bind_text(stmt, 2, account->account, -1, SQLITE_STATIC) != SQLITE_OK) {
		purple_debug_error("PidginCote", "PC_DBTable_Accounts_Insert: Unable to bind second value.\r\n");
		return FALSE;
	}

	// Execute query:
	if (sqlite3_step(stmt) != SQLITE_DONE) {
		purple_debug_error("PidginCote","PC_DBTable_Accounts_Insert: Unable to insert new entry.\r\n");
		sqlite3_finalize(stmt);
		return FALSE;
	} else {
		sqlite3_finalize(stmt);
		return TRUE;
	}
}



/**
 * Makes a new "Account" table entry.
 *
 * @returns The newly created Account entry or NULL on failure.
 */
static pc_dbtable_account* PC_DBTable_Accounts_New(void) {
	pc_dbtable_account*	retStruct;		// Clean-up: No

	// Make new struct:
	retStruct = g_new(pc_dbtable_account, 1);
	if (!retStruct) {
		purple_debug_error("PidginCote", "PC_DBTable_Accounts_New: Unable to allocate Account struct.\r\n");
		return NULL;
	}

	// Fill with default values:
	retStruct->id = 0;
	retStruct->account = NULL;
	retStruct->protocol = NULL;

	// Return new struct:
	return retStruct;
}


/**
 * Frees the memory allocated by the given Account struct.
 *
 * @param	account	The Account struct to free.
 */
static void PC_DBTable_Accounts_Delete(pc_dbtable_account* account) {
	// Check input:
	if (!account) {
		purple_debug_warning("PidginCote", "PC_DBTable_Accounts_Delete: Missing 'account' parameter.\r\n");
		return;
	}

	// Free members:
	g_free(account->account);
	g_free(account->protocol);
	account->account = NULL;
	account->protocol = NULL;

	// Free struct:
	g_free(account);
}


/**
 * Fetches one row from a statement as a Account entry.
 *
 * @param	stmt	The SQL statement from which one row will be parsed.
 * @returns	An Account entry corresponding to the first available row in the given statement.
 */
static pc_dbtable_account* PC_DBTable_Accounts_FetchOne(sqlite3_stmt* stmt) {
	int					sqlCode;	// Clean-up: No
	pc_dbtable_account*	retAccount;	// Clean-up: No
	int					colCount;	// Clean-up: No
	int					curCol;		// Clean-up: No
	const gchar*		colName;	// Clean-up: No

	// Check input:
	if (!stmt) {
		purple_debug_warning("PidginCote", "PC_DBTable_Accounts_FetchOne: Missing 'stmt' parameter.\r\n");
	}

	// Fetch one row:
	sqlCode = sqlite3_step(stmt);
	if (sqlCode == SQLITE_DONE) {
		// No more results available:
		purple_debug_info("PidginCote", "PC_DBTable_Accounts_FetchOne: No more available rows.\r\n");
		return NULL;
	} else if (sqlCode != SQLITE_ROW) {
		// Error occured:
		purple_debug_error("PidginCote", "PC_DBTable_Accounts_FetchOne: Unable to fetch row from statement.\r\n");
		return NULL;
	}

	// Prepare account object:
	retAccount = PC_DBTable_Accounts_New();
	if (!retAccount) {
		purple_debug_error("PidginCote", "PC_DBTable_Accounts_FetchOne: Unable to allocate account object.\r\n");
		return NULL;
	}

	// Cycle trough columns:
	colCount = sqlite3_column_count(stmt);
	for (curCol = 0; curCol < colCount; curCol++) {
		// Fetch column name:
		colName = sqlite3_column_name(stmt, curCol);
		if (strcmp(colName, "id") == 0) {
			retAccount->id = sqlite3_column_int(stmt, curCol);
		} else if (strcmp(colName, "protocol") == 0) {
			retAccount->protocol = g_strdup((const gchar*) (sqlite3_column_text(stmt, curCol)));
		} else if (strcmp(colName, "account") == 0) {
			retAccount->account = g_strdup((const gchar*) (sqlite3_column_text(stmt, curCol)));
		} else {
			purple_debug_warning("PidginCote", "PC_DBTable_Accounts_FetchOne: Unknown column '%s'.\r\n", colName);
		}
	}

	// Return result:
	return retAccount;
}
